package com.uto.backend;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.acl.LastOwnerException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpResponseException;
import org.apache.http.impl.client.BasicResponseHandler;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.RemoteException;
import android.util.Log;

import com.uto.User;
import com.uto.frontend.interfaces.IServiceListener;

public class HttpRequestBuilder {

	private static String TAG = "com.uto.backend.HttpRequestBuilder";

	public final static int TYPE_REGISTER = 0;
	public final static int TYPE_LOGIN = 1;
	public final static int TYPE_GET_AVILIABLE_MAPS = 2;
	public final static int TYPE_GET_AVILIABLE_GAMES = 3;
	public final static int TYPE_PLAYER_ACTION = 4;
	public final static int TYPE_LOCATION_CHANGED = 5;
	public final static int TYPE_START_NEW_GAME = 6;
	public final static int TYPE_JOIN_GAME = 7;
	public final static int TYPE_RANKING = 8;
	public final static int TYPE_SELL_STREET = 9;
	public final static int TYPE_BUY_STREET = 10;
	public final static int TYPE_UPDATE_GAME_DATA = 11;
	public final static int TYPE_DRAW_MAP = 12;
	public final static int TYPE_LOG = 13;


	private final String[] URL_CLASS = {
			"RegisterServlet",
			"LoginServlet",
			"",
			"GetAvailGames",
			"PlayerAction",
			"ChangeLocation",
			"startNewGame",
			"JoinGame",
			"GetPlayersRanking",
			"SellStreetServlet",
			"BuyServlet",
			"UpdateGameData",
			"ColorServlet",
			"GetEvents"}; 

	private final String URL_BASE = "http://94.159.131.109/Urban23082010";


	private int requestType;
	private IServiceListener listener;

	/**
	 * Builds and sends a request to the server.
	 * @param listener The listener waiting for the server response. 
	 * @param method The http method to use (currently Post of Get).
	 * @param requestType The type of request to send.
	 * @param urlParams parameters to add to the url line, null if none.
	 * @param data data to be sent in the body of the request, null if none (used only in Post requests).
	 */
	public void sendRequest(IServiceListener listener, String method , int requestType, Map<String,String> urlParams, JSONObject data){

		this.requestType = requestType;
		this.listener = listener;

		String url = URL_BASE + "/";
		url += URL_CLASS[requestType];

		if (urlParams!=null)
		{
			url += "?";
			Iterator<String> keys = urlParams.keySet().iterator();
			while (keys.hasNext()){
				String param = keys.next();
				url += param + "=";
				url += urlParams.get(param);
				if (keys.hasNext())
					url += "&";
			}
		}
		Log.d(TAG, url);
		HttpConnnectionThread httpThread = new HttpConnnectionThread(this , method , url , data);
		new Thread(httpThread).start();
	}

	public void handleResponse(HttpResponse httpResponse){

		boolean isOk;
		String message="";

		if (httpResponse==null){
			try {
				listener.handleMessage(null);
				return;
			} catch (RemoteException e) {
//				Log.e(TAG , e.getMessage());
				e.printStackTrace();
			}
		}

		Map<String,Object> data = null;

		if (httpResponse.getStatusLine().getStatusCode()>=300){
			isOk = false;
			try {
				ByteArrayOutputStream ostream = new ByteArrayOutputStream();
				httpResponse.getEntity().writeTo(ostream);
				message = ostream.toString();
				Log.v(TAG, "Reading message");
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (message==null)
				message = httpResponse.getStatusLine().getReasonPhrase(); 

			Log.v(TAG, "http error: " + httpResponse.getStatusLine().getStatusCode() + " : "+ message);

		}
		else{
			isOk = true;
			data = buildResponseData(httpResponse);
		}

		ServerResponse response = new ServerResponse(message,isOk , data);
		try {
			listener.handleMessage(response.getResponse());
		} catch (RemoteException e) {
			Log.e(TAG , e.getMessage());
			e.printStackTrace();
		}

	}

	//builds the data to be sent back to the frontend
	private Map<String, Object> buildResponseData(HttpResponse httpResponse) {
		HashMap<String , Object> data = new HashMap<String, Object>();

		//cases where there isn't supposed to be any data
		if (requestType == TYPE_REGISTER || requestType == TYPE_START_NEW_GAME
				|| requestType==TYPE_JOIN_GAME || requestType==TYPE_SELL_STREET)
			return null;

		String result = null;

		try {

			result = new BasicResponseHandler().handleResponse(httpResponse);

		} catch (Exception e) {
			e.printStackTrace();
			Log.e(TAG , e.getMessage());
			return null;
		}

		Log.v(TAG, "http response: " + result);

		switch (requestType){
		case TYPE_GET_AVILIABLE_GAMES:
			//send the whole response string to the activity.
			//the activity will parse it into an array of games (and display it as an expandable list)
			data.put("games", result);
			break;

		case TYPE_GET_AVILIABLE_MAPS:

			break;
			
		case TYPE_DRAW_MAP:
			try{
				Log.d(TAG,"get correct response Draw Map");
				JSONArray array = new JSONArray(result);
				String color;
				String lineArr;
				for (int i = 0; i < array.length(); i++) {
					String res=array.getString(i);
					JSONObject curObj = new JSONObject(res);
					color=curObj.getString("playerColor");
					lineArr=curObj.getString("coordinates");
					data.put("color"+i, color);
					data.put("line"+i, lineArr);
					Log.d(TAG,"color is: "+color+" line is: "+lineArr);
				}
			}catch (Exception e) {
				Log.d(TAG, e.getMessage());
			}
			break;
		case TYPE_LOGIN:
			try {
				JSONArray array = new JSONArray(result);
				String userString = array.getString(0);
				JSONObject curObj = new JSONObject(userString);
				data.put("money", curObj.getInt("money"));
				data.put("streets", curObj.getJSONArray("ownedStreets"));

			} catch (Exception e) {
				Log.d(TAG, e.getMessage());
			}

			break;

		case TYPE_LOCATION_CHANGED:
			break;

		case TYPE_LOG:
			try{
				Log.d(TAG,"get correct response log");
				JSONArray array = new JSONArray(result);
				String type="";
				String msg = "";
				int typeNum=0;
				for (int i = 0; i < array.length(); i++) {
					String res=array.getString(i);
					JSONObject curObj = new JSONObject(res);
					type=" "+curObj.getString("msgType");
					if (type.equals(" SELL")) {
						typeNum=0;
					}
					else if (type.equals(" BUY")) {
						typeNum=1;
					}
					else if (type.equals(" PAY")) {
						typeNum=2;
					}
					else if (type.equals(" COLLECT")) {
						typeNum=3;
					}
					
					msg=" "+curObj.getString("msg");
					data.put("msgType"+i, typeNum);
					data.put("msg"+i, msg);
					Log.d(TAG,type+" "+msg+" "+typeNum);
					Log.d(TAG,type);
				}
			}catch (Exception e) {
				Log.d(TAG, e.getMessage());
			}
			break;

		case TYPE_PLAYER_ACTION:
			break;

		case TYPE_BUY_STREET:
			data.put("buyMsg", result);
			break;

		case TYPE_UPDATE_GAME_DATA:
			try {
				JSONArray array = new JSONArray(result);
				Log.d(TAG, "HttpBuilder Update Data");
				String userString = array.getString(0);
				JSONObject curObj = new JSONObject(userString); //curUser.
				String userName = curObj.getString("userName");
				Log.d(TAG, userName);
				String firstName = curObj.getString("firstName");
				Log.d(TAG, firstName);
				String lastName = curObj.getString("lastName");
				Log.d(TAG, lastName);
				String password = curObj.getString("password");
				Log.d(TAG, password);
				String money = curObj.getString("money");
				Log.d(TAG, money);
				String streets = curObj.getString("ownedStreets");
				Log.d(TAG, streets);
				User curUser = new User(userName,password,firstName,lastName,Integer.parseInt(money),streets);
				//				User curUser = new User(userName,password,firstName,lastName,555,streets);

				if (curUser== null) {
					Log.d(TAG, "curUserIsNull!!");
				}
				data.put("curUser", curUser);
			}catch (Exception e) {
				Log.d(TAG, e.getMessage());
			}

			break;

		case TYPE_RANKING:
			try{
				//Adding the users data to the map with key userX  (starting from 0)
				//and data is the given data.
				Log.d(TAG,"get correct response ranking");
				JSONArray array = new JSONArray(result);
				for (int i = 0; i < array.length(); i++) {
					String res=array.getString(i);
					JSONObject curObj = new JSONObject(res);
					res=" "+curObj.getString("firstName");
					res+=" "+curObj.getString("lastName");
					res+=" "+curObj.getString("money");
					data.put("user"+i, res);	
					Log.d(TAG,res);
				}
			}catch (Exception e) {
				Log.e(TAG, e.getMessage());
			}
			break;
		}
		return data;
	}

}
